/*   The MIT License
 *   
 *   Carina Engine
 *   Copyright (c) 2009 2010 2011 2012 Zdravko Velinov
 *   
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#ifndef RENDERER_BASE_HH_
#define RENDERER_BASE_HH_

#include "carina/common/global.hh"
#include "carina/common/containers.hh"
#include "carina/common/patterns.hh"
#include "carina/common/types.hh"
#include "carina/math.hh"

namespace Carina
{
class InputLayout;
typedef shared_ptr<InputLayout> InputLayoutPtr;
typedef shared_ptr<const InputLayout> InputLayoutConstPtr;

class VideoBuffer;
typedef shared_ptr<VideoBuffer> VideoBufferPtr;
typedef shared_ptr<const VideoBuffer> VideoBufferConstPtr;

class ShaderProgram;
typedef shared_ptr<ShaderProgram> ShaderProgramPtr;

class Texture;
typedef shared_ptr<Texture> TexturePtr;
typedef shared_ptr<const Texture> TextureConstPtr;

class StateObject;
typedef shared_ptr<StateObject> StateObjectPtr;

class BlendStateObject;
typedef shared_ptr<BlendStateObject> BlendStateObjectPtr;

class DepthStencilStateObject;
typedef shared_ptr<DepthStencilStateObject> DepthStencilStateObjectPtr;

class Framebuffer;
typedef shared_ptr<Framebuffer> FramebufferPtr;

enum VarType
{
    VT_UNKNOWN,
    VT_R32F,
    VT_RG32F,
    VT_RGB32F,
    VT_RGBA32F,
    VT_R16F,
    VT_RG16F,
//  VT_RGB16F,
    VT_RGBA16F,
    VT_R32,
    VT_RG32,
    VT_RGB32,
    VT_RGBA32,
    VT_R16,
    VT_RG16,
//  VT_RGB16,
    VT_RGBA16,
    VT_R8,
    VT_RG8,
//  VT_RGB8,
    VT_RGBA8,
    VT_uR32,
    VT_uRG32,
    VT_uRGB32,
    VT_uRGBA32,
    VT_uR16,
    VT_uRG16,
//  VT_uRGB16,
    VT_uRGBA16,
    VT_uR8,
    VT_uRG8,
//  VT_uRGB8,
    VT_uRGBA8,
    
    VT_R16_SNORM,
    VT_RG16_SNORM,
//  VT_RGB16_SNORM,
    VT_RGBA16_SNORM,
    VT_R8_SNORM,
    VT_RG8_SNORM,
//  VT_RGB8_SNORM,
    VT_RGBA8_SNORM,
    VT_R16_UNORM,
    VT_RG16_UNORM,
//  VT_RGB16_UNORM,
    VT_RGBA16_UNORM,
    VT_R8_UNORM,
    VT_RG8_UNORM,
//  VT_RGB8_UNORM,
    VT_RGBA8_UNORM,

    VT_D16,
    VT_D24S8,
    VT_D32,

    VT_R10G10B10A2,
    VT_UINT_R10G10B10A2
};

size_t SizeofVarType(VarType vt);

enum IndicesType
{
    IT_UBYTE,
    IT_USHORT,
    IT_UINT
};

enum VBType
{
    CE_VERTEX_BUFFER,
    CE_INDEX_BUFFER
};

enum VBUsage
{
    CE_STATIC_DRAW,
    CE_STATIC_READ,
    CE_STATIC_COPY,
    CE_STREAM_DRAW,
    CE_STREAM_READ,
    CE_STREAM_COPY,
    CE_DYNAMIC_DRAW,
    CE_DYNAMIC_READ,
    CE_DYNAMIC_COPY
};

enum DrawModes
{
    CE_POINT_LIST,
    CE_LINE_STRIP,
    CE_LINE_LIST,
    CE_TRIANGLE_STRIP,
    CE_TRIANGLE_LIST,
    CE_LINE_STRIP_ADJ,
    CE_LINE_LIST_ADJ,
    CE_TRIANGLE_STRIP_ADJ,
    CE_TRIANGLE_LIST_ADJ
};

enum UniformVarType
{
    CE_UVT_UNKNOWN,
    CE_UVT_FLOAT,
    CE_UVT_VEC2,
    CE_UVT_VEC3,
    CE_UVT_VEC4,
    CE_UVT_INT,
    CE_UVT_IVEC2,
    CE_UVT_IVEC3,
    CE_UVT_IVEC4,
    CE_UVT_UINT,
    CE_UVT_UVEC2,
    CE_UVT_UVEC3,
    CE_UVT_UVEC4,
    CE_UVT_BOOL,
    CE_UVT_BVEC2,
    CE_UVT_BVEC3,
    CE_UVT_BVEC4,
    CE_UVT_MAT2,
    CE_UVT_MAT3,
    CE_UVT_MAT4,
    CE_UVT_MAT2x3,
    CE_UVT_MAT2x4,
    CE_UVT_MAT3x2,
    CE_UVT_MAT3x4,
    CE_UVT_MAT4x2,
    CE_UVT_MAT4x3,
    CE_UVT_TEXTURE,
	CE_UVT_STRUCT
};

template<class T>
struct UVTInfo;

#define UVT_ENUM_BIND(type, val, len) \
template<> struct UVTInfo<type> { \
    inline static UniformVarType value() { return val; } \
    inline static size_t length() { return len; } \
};

UVT_ENUM_BIND(TexturePtr, CE_UVT_TEXTURE, 1)
UVT_ENUM_BIND(float, CE_UVT_FLOAT, 1)
UVT_ENUM_BIND(Vector2, CE_UVT_VEC2, 1)
UVT_ENUM_BIND(Vector3, CE_UVT_VEC3, 1)
UVT_ENUM_BIND(Vector4, CE_UVT_VEC4, 1)
UVT_ENUM_BIND(Matrix4, CE_UVT_MAT4, 1)
UVT_ENUM_BIND(int32, CE_UVT_INT, 1)
UVT_ENUM_BIND(uint32, CE_UVT_UINT, 1)
UVT_ENUM_BIND(Quaternion, CE_UVT_VEC4, 1)
UVT_ENUM_BIND(DualQuaternion, CE_UVT_VEC4, 2)

struct InputElement
{
    string      m_Name;
    VarType     m_Type;
    size_t      m_Offset;

    InputElement() {}

    InputElement(const string& n, VarType t, size_t off)
        :   m_Name(n),
            m_Type(t),
            m_Offset(off) {}

    InputElement(const InputElement& ie)
        :   m_Name(ie.m_Name),
            m_Type(ie.m_Type),
            m_Offset(ie.m_Offset) {}

    InputElement& operator=(const InputElement& ie)
    {
        m_Name = ie.m_Name;
        m_Type = ie.m_Type;
        m_Offset = ie.m_Offset;
        return *this;
    }

    void set(const string& name, VarType type, size_t offset) { m_Name = name, m_Type = type, m_Offset = offset; }
};

typedef DynamicArray<InputElement> InputElementArray;

enum PolygonFace
{
    CE_CULL_NONE=0,
    CE_CULL_FRONT,
    CE_CULL_BACK
};

enum FillMode
{
    CE_FILL_WIREFRAME,
    CE_FILL_SOLID
};

enum CEBlend
{
    CE_BLEND_ZERO,
    CE_BLEND_ONE,
    CE_BLEND_SRC_COLOR,
    CE_BLEND_INV_SRC_COLOR,
    CE_BLEND_SRC_ALPHA,
    CE_BLEND_INV_SRC_ALPHA,
    CE_BLEND_DEST_ALPHA,
    CE_BLEND_INV_DEST_ALPHA,
    CE_BLEND_DEST_COLOR,
    CE_BLEND_INV_DEST_COLOR,
    CE_BLEND_SRC_ALPHA_SAT,
//  CE_BLEND_BLEND_FACTOR, // TODO: I will support it later
//  CE_BLEND_INV_BLEND_FACTOR,
    CE_BLEND_SRC1_COLOR,
    CE_BLEND_INV_SRC1_COLOR,
    CE_BLEND_SRC1_ALPHA,
    CE_BLEND_INV_SRC1_ALPHA
};

enum CEBlendOperation
{
    CE_BLEND_OP_ADD,
    CE_BLEND_OP_SUBTRACT,
    CE_BLEND_OP_REV_SUBTRACT,
    CE_BLEND_OP_MIN,
    CE_BLEND_OP_MAX
};

enum CECompFunc
{
    CE_CMP_NEVER,
    CE_CMP_LESS,
    CE_CMP_EQUAL,
    CE_CMP_LESS_EQUAL,
    CE_CMP_GREATER,
    CE_CMP_NOT_EQUAL,
    CE_CMP_GREATER_EQUAL,
    CE_CMP_ALWAYS
};

enum CEStencilOperation
{
    CE_STENCIL_OP_KEEP,
    CE_STENCIL_OP_ZERO,
    CE_STENCIL_OP_REPLACE,
    CE_STENCIL_OP_INCR_SAT,
    CE_STENCIL_OP_DECR_SAT,
    CE_STENCIL_OP_INVERT,
    CE_STENCIL_OP_INCR,
    CE_STENCIL_OP_DECR
};

struct Rect
{
    int x0, y0,
        x1, y1;

    Rect(int _x0, int _y0, int _x1, int _y1)
        :   x0(_x0), y0(_y0),
            x1(_x1), y1(_y1) {}
};

enum CEBufferBit
{
    CE_COLOR_BUFFER_BIT   = 1,
    CE_DEPTH_BUFFER_BIT   = 1 << 1
//  CE_STENCIL_BUFFER_BIT = 1 << 2
};

enum CETextureFlags
{
    CE_TEXTURE_ARRAY    = 1,
    CE_TEXTURE_CUBE     = 1 << 1,
    CE_GENERATE_MIPS    = 1 << 2
};

class ShaderCompiler
{
    string                  m_Name;
public:
    ShaderCompiler(const string& name)
        :   m_Name(name) {}
    virtual ~ShaderCompiler() {}

    string getName() const { return m_Name; }
    virtual ShaderProgramPtr compileShaderProgram(const string& filename) const=0;
};

typedef shared_ptr<ShaderCompiler> ShaderCompilerPtr;

typedef DataVector<string> ShadingLanguagesList;

class IncludeLoader
{
public:
    virtual bool loadInclude(const string& filename, const char** contents, size_t& contents_size)=0;
    virtual void freeInclude(const char* contents)=0;
};

typedef shared_ptr<IncludeLoader> IncludeLoaderPtr;

struct MiscStateDescription
{
	FillMode    PolygonFillMode;
    PolygonFace CullPolygonFace;
    float		DepthBiasFactor;
    float		DepthBiasUnits;
    bool		DepthClip;
    bool		ScissorTest;
    bool		MultiSampling;
    bool		LinesAntiAliasing;

	MiscStateDescription(FillMode mode = CE_FILL_SOLID,
		  				 PolygonFace cull_face = CE_CULL_BACK,
						 float dbias_factor = 0,
						 float dbias_units = 0,
						 bool depth_clip = true,
						 bool scissor = false,
						 bool multisample = false,
						 bool aa_lines = false)
		:	PolygonFillMode(mode),
			CullPolygonFace(cull_face),
			DepthBiasFactor(dbias_factor),
			DepthBiasUnits(dbias_units),
			DepthClip(depth_clip),
			ScissorTest(scissor),
			MultiSampling(multisample),
			LinesAntiAliasing(aa_lines) {}
};

struct BlendStateDescription
{
	bool			 BlendEnabled;
	CEBlend			 SrcBlend;
	CEBlend			 DstBlend;
	CEBlendOperation BlendOp;
	CEBlend			 SrcBlendAlpha;
	CEBlend			 DstBlendAlpha;
	CEBlendOperation BlendAlphaOp;

	BlendStateDescription(bool enabled = false,
						  CEBlend srcblend = CE_BLEND_ONE,
						  CEBlend dstblend = CE_BLEND_ZERO,
						  CEBlendOperation blendop = CE_BLEND_OP_ADD,
						  CEBlend srcblendalpha = CE_BLEND_ONE,
						  CEBlend dstblendalpha = CE_BLEND_ZERO,
						  CEBlendOperation alphaop = CE_BLEND_OP_ADD)
	:	BlendEnabled(enabled),
		SrcBlend(srcblend),
		DstBlend(dstblend),
		BlendOp(blendop),
		SrcBlendAlpha(srcblendalpha),
		DstBlendAlpha(dstblendalpha),
		BlendAlphaOp(alphaop) {}
};

struct DepthStencilStateDescription
{
	bool			   DepthTest;
	bool			   DepthMask; 
	CECompFunc		   DepthFunc;
	bool			   StencilTest;
	char			   StencilMask;
	CEStencilOperation FrontStencilFail;
	CEStencilOperation FrontStencilDepthFail;
	CEStencilOperation FrontStencilDepthPass;
	CECompFunc		   FrontStencilFunc;
	CEStencilOperation BackStencilFail;
	CEStencilOperation BackStencilDepthFail;
	CEStencilOperation BackStencilDepthPass;
	CECompFunc		   BackStencilFunc;
	int				   StencilRef;

	DepthStencilStateDescription(bool depth_test = true,
								 bool depth_mask = true,
								 CECompFunc depth_func = CE_CMP_LESS,
								 bool stencil_test = false,
								 char stencil_mask = 0x0,
								 CEStencilOperation sfront_sfail = CE_STENCIL_OP_KEEP,
								 CEStencilOperation sfront_dpfail = CE_STENCIL_OP_KEEP,
								 CEStencilOperation sfront_dppass = CE_STENCIL_OP_KEEP,
								 CECompFunc sfront_func = CE_CMP_ALWAYS,
								 CEStencilOperation sback_sfail = CE_STENCIL_OP_KEEP,
								 CEStencilOperation sback_dpfail = CE_STENCIL_OP_KEEP,
								 CEStencilOperation sback_dppass = CE_STENCIL_OP_KEEP,
								 CECompFunc sback_func = CE_CMP_ALWAYS,
								 int sref = 0)
		:	DepthTest(depth_test),
			DepthMask(depth_mask),
			DepthFunc(depth_func),
			StencilTest(stencil_test),
			StencilMask(stencil_mask),
			FrontStencilFail(sfront_sfail),
			FrontStencilDepthFail(sfront_dpfail),
			FrontStencilDepthPass(sfront_dppass),
			FrontStencilFunc(sfront_func),
			BackStencilFail(sfront_sfail),
			BackStencilDepthFail(sfront_dpfail),
			BackStencilDepthPass(sfront_dppass),
			BackStencilFunc(sfront_func),
			StencilRef(sref) {}
};

struct TextureDescription
{
	size_t  Width,
			Height,
			Depth,
			Samples;
	VarType Format;
	
	TextureDescription(size_t width, size_t height, size_t depth, VarType format, size_t samples = 1)
		:	Width(width),
			Height(height),
			Depth(depth),
			Samples(samples),
			Format(format) {}
};

// Fixme: god object
class RendererBase: public non_copyable
{
public:
    RendererBase() {}

    virtual ~RendererBase() {}

    virtual InputLayoutPtr createInputLayout(const ShaderProgramPtr& shader, const InputElementArray&)=0;
    virtual void setInputLayout(const InputLayoutConstPtr& layout)=0;

    virtual VideoBufferPtr createVideoBuffer(VBType type, size_t size, const void* data, VBUsage usage)=0;
    virtual void setVideoBuffer(const VideoBufferPtr& vb, size_t stride, size_t offset=0)=0;
    virtual void setIndexBuffer(const VideoBufferPtr& vb, IndicesType itype, size_t offset=0)=0;

    virtual void draw(DrawModes mode, size_t first, size_t count)=0;
    virtual void drawIndexed(DrawModes mode, size_t first, size_t count)=0;

    virtual ShaderCompilerPtr getPreferredShaderCompiler(const ShadingLanguagesList& shlang_list)=0;
    virtual ShaderCompilerPtr getShaderCompiter(const string& shading_language)=0;
    virtual void setPreferredShadingLanguage(const string& name)=0;
    virtual void useShaderProgram(const ShaderProgramPtr& prog)=0;

    virtual TexturePtr createTexture(const TextureDescription& desc, const void* data, int flags)=0;

    virtual void resizeViewport(size_t w, size_t h)=0;
    virtual void getViewport(size_t& w, size_t& h)=0;

    virtual StateObjectPtr createStateObject(const MiscStateDescription& desc)=0;
    virtual void setStateObject(const StateObjectPtr& state_obj)=0;
    virtual StateObjectPtr getStateObject()=0;

    virtual void setScissorRect(size_t x, size_t y, size_t width, size_t height)=0;

    virtual BlendStateObjectPtr createBlendStateObject(const BlendStateDescription& desc)=0;
    virtual void setBlendStateObject(const BlendStateObjectPtr& bstate_obj)=0;
    virtual BlendStateObjectPtr getBlendStateObject()=0;

    virtual DepthStencilStateObjectPtr createDepthStencilStateObject(const DepthStencilStateDescription& desc)=0;
    virtual void setDepthStencilStateObject(const DepthStencilStateObjectPtr& dsstate_obj)=0;
    virtual DepthStencilStateObjectPtr getDepthStencilStateObject()=0;

    virtual FramebufferPtr createFramebuffer()=0;
    virtual void bindFramebuffer(const FramebufferPtr& fb)=0;
    virtual void bindDrawFramebuffer(const FramebufferPtr& fb)=0;
    virtual void bindReadFramebuffer(const FramebufferPtr& fb)=0;
    virtual void blitFramebuffer(int buffers)=0;
    virtual FramebufferPtr getDrawFramebuffer()=0;
    virtual FramebufferPtr getReadFramebuffer()=0;

    virtual Vector4 getClearColor() const=0;
    virtual void setClearColor(const Vector4& color)=0;
    virtual void clearColorBuffer(size_t idx, const Vector4& color)=0;
    virtual void clearDepthStencilBuffer(float depth=1.0f, int stencil=0)=0;
    virtual void clearAll()=0;

    virtual void registerIncludeLoader(const IncludeLoaderPtr& include_loader)=0;
    virtual IncludeLoaderPtr getIncludeLoader()=0;

    virtual Matrix4 createPerspectiveMatrix(float fovy, float aspect, float zNear, float zFar)=0;
    virtual Matrix4 createOrthoMatrix(float left, float right, float bottom, float top, float _near=-1.0f, float _far=1.0f)=0;
};

class WindowImpl;
typedef shared_ptr<WindowImpl> WindowImplPtr;

class RenderingLibrary
{
    string  m_Name;
public:
    RenderingLibrary(const string& name);
    virtual ~RenderingLibrary() {}

    string getName() const { return m_Name; }
    virtual WindowImplPtr createWindowImpl()=0;
};

typedef shared_ptr<RenderingLibrary> RenderingLibraryPtr;

class RenderingSubsystem
{
    DynamicArray<RenderingLibraryPtr> m_Libraries;
public:
    RenderingSubsystem();

    size_t getLibraryCount() const { return m_Libraries.size(); }
    RenderingLibraryPtr getLibrary(size_t idx);
    RenderingLibraryPtr getLibrary(const string& name);
};

typedef shared_ptr<RendererBase> RendererPtr;

class StateObject
{
public:
    virtual ~StateObject()=0;
};

class BlendStateObject
{
public:
    virtual ~BlendStateObject()=0;
};

class DepthStencilStateObject
{
public:
    virtual ~DepthStencilStateObject()=0;
};

#define SCOPED_STATE_TYPE(name) \
class Scoped##name \
{ \
    RendererPtr     m_Renderer; \
    name##ObjectPtr m_PrevState; \
public: \
    Scoped##name(const RendererPtr& renderer) \
        :   m_Renderer(renderer) {} \
    Scoped##name(const RendererPtr& renderer, const name##ObjectPtr& current) \
        :   m_Renderer(renderer), \
            m_PrevState(renderer->get##name##Object()) \
    { \
        renderer->set##name##Object(current); \
    } \
    ~Scoped##name() { m_Renderer->set##name##Object(m_PrevState); } \
    void setState(const name##ObjectPtr& state) \
    { \
        assert(!m_PrevState.get()); \
        m_PrevState = m_Renderer->get##name##Object(); \
        m_Renderer->set##name##Object(state); \
    } \
}

SCOPED_STATE_TYPE(State);
SCOPED_STATE_TYPE(BlendState);
SCOPED_STATE_TYPE(DepthStencilState);

class InputLayout: public non_copyable
{
    friend class RendererBase;
public:
    InputLayout() {}
    virtual ~InputLayout()=0;
};

class VideoBuffer: public non_copyable
{
    friend class RendererBase;
public:
    VideoBuffer() {}
    virtual ~VideoBuffer()=0;
};

class Texture: public non_copyable
{
public:
    Texture() {}
    virtual ~Texture() {}
};

// TODO: that doesn't look good
class UniformVar: public non_copyable
{
public:
    UniformVar() {}
    virtual ~UniformVar() {}

    virtual void set(uint32 i)=0;
    virtual void set(const uint32* const arr, size_t N)=0;
    virtual void set(int32 i)=0;
    virtual void set(const int32* const arr, size_t N)=0;
    virtual void set(const Quaternion* const arr, size_t N)=0;
    virtual void set(const DualQuaternion* const arr, size_t N)=0;
    virtual void set(const Matrix4* const arr, size_t N)=0;
    virtual void set(const Vector4* const arr, size_t N)=0;
    virtual void set(const Vector3* const arr, size_t N)=0;
    virtual void set(const Vector2* const arr, size_t N)=0;
    virtual void set(const float* const arr, size_t N)=0;

    virtual void set(const Vector4& vec)=0;
    virtual void set(const Vector3& vec)=0;
    virtual void set(const Vector2& vec)=0;
    virtual void set(float f)=0;
    virtual void set(const Matrix4& mat)=0;
    virtual void set(const DualQuaternion& dq)=0;
    virtual void set(const Quaternion& q)=0;

    template<class T>
        inline void set(const DynamicArray<T>& arr) { this->set(arr.get(), arr.size()); }

    virtual void get(uint32& i) const=0;
    virtual void get(uint32* const arr, size_t N) const=0;
    virtual void get(int32& i) const=0;
    virtual void get(int32* const arr, size_t N) const=0;
    virtual void get(Quaternion* const arr, size_t N) const=0;
    virtual void get(DualQuaternion* const arr, size_t N) const=0;
    virtual void get(Matrix4* const arr, size_t N) const=0;
    virtual void get(Vector4* const arr, size_t N) const=0;
    virtual void get(Vector3* const arr, size_t N) const=0;
    virtual void get(Vector2* const arr, size_t N) const=0;
    virtual void get(float* const arr, size_t N) const=0;

    virtual void get(Vector4& vec) const=0;
    virtual void get(Vector3& vec) const=0;
    virtual void get(Vector2& vec) const=0;
    virtual void get(float& f) const=0;
    virtual void get(Matrix4& mat) const=0;
    virtual void get(DualQuaternion& dq) const=0;
    virtual void get(Quaternion& q) const=0;

    template<class T>
        inline void get(DynamicArray<T>& arr) const { this->set(arr.get(), arr.size()); }
};

typedef shared_ptr<UniformVar> UniformVarPtr;

class TextureVar: public non_copyable
{
public:
    TextureVar() {}
    virtual ~TextureVar() {}

    virtual void reset()=0;
    virtual void set(const TexturePtr& tex)=0;
    virtual void set(TexturePtr* arr, size_t N)=0;
    inline void set(DynamicArray<TexturePtr>& arr) { this->set(arr.get(), arr.size()); }
};

typedef shared_ptr<TextureVar> TextureVarPtr;

struct UniformVarTypeDesc
{
    size_t          size;
    UniformVarType  type;

	// MSVC has some problems with initializer lists, so this is kind of necessary.
	UniformVarTypeDesc() {}
	UniformVarTypeDesc(size_t _size, UniformVarType _type)
		:	size(_size),
			type(_type) {}
};

class ShaderProgram: public non_copyable
{
public:
    ShaderProgram() {}
    virtual ~ShaderProgram() {}

    virtual void useTechnique(const string& name)=0;

    virtual UniformVarPtr getVariable(const string& name)=0;
    virtual TextureVarPtr getTexture(const string& name)=0;

    virtual void getVariableType(const string& name, UniformVarTypeDesc& desc)=0;

#ifdef CE_RELOADABLE_RESOURCES
    virtual void reload(const string& filename)=0;
#endif

    virtual void apply() const=0;
};

struct FBAttachmentInfo
{
    TexturePtr  texture;
    size_t      level;
    size_t      layer;

    FBAttachmentInfo() {}
    FBAttachmentInfo(const TexturePtr& _texture, size_t _level=0, size_t _layer=0)
        :   texture(_texture),
            level(_level),
            layer(_layer) {}
};

typedef DynamicArray<FBAttachmentInfo> FBAttachmentArray;

class Framebuffer: public non_copyable
{
public:
    virtual ~Framebuffer() {}

    virtual void attachDepthStencilTexture(const FBAttachmentInfo& texture)=0;
    virtual void attachTextures(const FBAttachmentArray& textures)=0;

    virtual bool validate()=0;
};
}

#endif /* RENDERER_BASE_HH_ */
